// 模拟人类
import snowId from '@/utils/snowId';
import AStar from '@/utils/aStar';

interface SimpleHuman {
    isAlive(): boolean;

    action(times: number, humans: Human[], width: number, height: number): void;

    getInstance(): Human
}

class BaseHuman {
    protected id: number;
    protected name: string;
    protected gender: number;
    protected birthday: number;
    protected age: number;
    protected maxAge: number;

    protected posX: number = 0;
    protected posY: number = 0;
    protected desPosX: number = -1;
    protected desPosY: number = -1;
    protected restTime: number = 0;

    constructor(times: number, name: string = '', gender: number = 0) {
        this.id = snowId.nextId();
        this.name = name || this.createName();
        this.gender = gender || this.createGender();
        this.birthday = times;
        this.age = 0;
        this.maxAge = Math.floor(20 + Math.random() * 60);
    }

    private createName(): string {
        // 随机生成一个名字
        return '未命名';
    }

    private createGender(): number {
        // 随机生成一个性别
        return Math.ceil(Math.random() * 2);
    }

    getId(): number {
        return this.id;
    }

    getName(): string {
        return this.name;
    }

    getGender(): number {
        return this.gender;
    }

    getAge(): number {
        return this.age;
    }

    setAge(times: number): void {
        this.age = Math.floor((times - this.birthday) / 1200);//12小时=1天，100天=1年
    }

    isAlive(): boolean {
        return this.age < this.maxAge;
    }

    getPos() {
        return { x: this.posX, y: this.posY }
    }

    setPos(x: number, y: number): void {
        this.posX = x;
        this.posY = y;
    }

    isMoving(): boolean {
        // 判断是否在移动
        return this.desPosX >= 0 && this.desPosY >= 0;
    }

    startMove(width: number, height: number): void {
        // 开始移动
        const { x, y } = this.createRandomDesPos(width, height);
        this.desPosX = x;
        this.desPosY = y;
    }

    createRandomDesPos(width: number, height: number): { x: number, y: number } {
        // 随机生成一个目的地
        const x = this.posX + (Math.random() > 0.5 ? -1 : 1) * (Math.floor(Math.random() * 20) + 5);
        const y = this.posY + (Math.random() > 0.5 ? -1 : 1) * (Math.floor(Math.random() * 20) + 5);
        if (x < 0 || x >= width || y < 0 || y >= height)
            return this.createRandomDesPos(width, height);
        return { x, y };
    }

    move(humans: Human[]): void {
        // 移动
        const startX = Math.min(this.posX, this.desPosX);
        const startY = Math.min(this.posY, this.desPosY);
        const endX = Math.max(this.posX, this.desPosX);
        const endY = Math.max(this.posY, this.desPosY);

        const grid: number[][] = []
        for (let i = 0; i < endX - startX + 1; i++) {
            grid[i] = [];
            for (let j = 0; j < endY - startY + 1; j++) {
                grid[i][j] = 0;
            }
        }
        for (let i = 0; i < humans.length; i++) {
            const human = humans[i];
            const { x, y } = human.getPos();
            if (x >= startX && x <= endX && y >= startY && y <= endY) {
                grid[x - startX][y - startY] = 1;
            }
        }
        const astar = new AStar(grid, this.posX - startX, this.posY - startY, this.desPosX - startX, this.desPosY - startY);
        const path = astar.findPath();
        if (path && path.length > 1) {
            const nextPos = path[1];
            this.setPos(startX + nextPos.x, startY + nextPos.y);
            if (this.posX === this.desPosX && this.posY === this.desPosY) {
                this.desPosX = -1;
                this.desPosY = -1;
            }
        }
    }

    isResting(): boolean {
        // 判断是否在休息
        return this.restTime > 0;
    }

    startRest(): void {
        // 开始休息
        this.restTime = Math.floor(Math.random() * 10) + 5;
    }

    rest(): void {
        // 休息
        this.restTime--;
    }
}

class Human extends BaseHuman implements SimpleHuman {
    action(times: number, humans: Human[], width: number, height: number): void {
        this.setAge(times)

        if (this.isDoing()) {
            if (this.isMoving()) this.move(humans);
            if (this.isResting()) this.rest();
        }
        else {
            const state = Math.floor(Math.random() * 3);

            switch (state) {
                case 1:
                    // 移动
                    this.startMove(width, height)
                    break;
                case 2:
                    // 休息
                    this.startRest()
                    break;
                default:
                    // 什么都不做
                    break;
            }
        }
    }

    private isDoing(): boolean {
        return this.isMoving() || this.isResting();
    }

    getInstance(): Human {
        return this;
    }
}

const createHuman = (times: number, posX: number, posY: number, name: string = '', gender: number = 0): SimpleHuman => {
    const human = new Human(times, name, gender);
    human.setPos(posX, posY);
    return human;
}


export type { SimpleHuman };

export { createHuman };
